<template>
  <div>
    <input type="text" @input="handleSearch">
    <!-- 当window.devicePixelRatio为2的时候 -->
    <!-- <canvas ref="canvas" width="1600" height="1200">对不起，您的浏览器不支持</canvas> -->
    <!-- <canvas ref="canvas" width="800" height="600">对不起，您的浏览器不支持</canvas> -->
    <!-- 当window.devicePixelRatio为1.25的时候 -->
    <canvas ref="canvas" :width="800*pixelRatio" :height="600*pixelRatio">对不起，您的浏览器不支持</canvas>
  </div>
</template>

<script setup>
// 为了获取到canvas dom
import {ref,onMounted,onUnmounted,reactive,watch} from 'vue'

// 定义事件
defineEmits('click')


// 获取canvas dom引用
// 注意一定不要用dom操作
// const canvas = document.querySelector("#canvas")

//ts写法：
// const canvas = ref<HTMLCanvasElement|null>(null)
// 这里直接
const canvas = ref(null)

const pixelRatio=window.devicePixelRatio
console.log("pixelRatio",pixelRatio);

const cellWidth = 100 * pixelRatio
const cellHeight = 50 * pixelRatio

// 当前可视区域
let startRow=0;

const visableRows = Math.ceil(600*pixelRatio/cellHeight)-1 //可视区域：高度/单元格宽度-1(表头那一行)
const selectedCell = reactive({row:-1,column:-1})  

// 响应式数据
// 数据跟UI本身没有关系
// 我们做筛选，影响的是数据
const d={
  columns:[{
    title: '姓名',
    key: 'name',
    width: 100
  },{
    title: '年龄',
    key: 'age',
    width: 100
  }],
  dataSource: Array.from({length: 1000}).map((item,index)=>({
    key:index,
    name:`name-${index}`,
    age: Math.floor(Math.random() * 100)
  })),
}

const data = reactive({
  ...d,
  tmpDataSource:d.dataSource,
})

const handleClick=(ev)=>{
  // 当前点了哪里
  const {left,top}=canvas.value.getBoundingClientRect()   //画布距离屏幕左边，顶部的距离
  const x=ev.clientX-left  //鼠标距离屏幕左边的距离-画布距离屏幕左边的距离=》鼠标距离画布左侧的长度
  const y=ev.clientY-top  //鼠标距离屏幕顶部的距离-画布距离屏幕顶部的长度=》鼠标距离画布顶部的长度  

  // 判断我点的x和y，落到了哪个单元格下  碰撞检测的问题
  // const rowIndex=Math.floor(y*1.25/cellHeight)-1  //再减去一个表格头部（头部不算）
  const rowIndex=Math.floor(y*pixelRatio/cellHeight)-1+startRow  //再减去一个表格头部（头部不算）  加startRow是为了要知道她真实行的index
  console.log("x,y",x,y);
  // const colIndex=Math.floor(x*1.25/cellWidth)
  const colIndex=Math.floor(x*pixelRatio/cellWidth)
  console.log("rowIndex,colIndex",rowIndex,colIndex);

  // 我只需要判断 rowIndex >= 0 rowIndex < data.dataSource.length 说明被选中
  if(rowIndex>=0 && rowIndex<data.dataSource.length){
    // 说明有单元格被选中
    selectedCell.row=rowIndex
    selectedCell.column=colIndex

    // this.$emit('click')

    // 重绘表格
    drawTable()
  }
}

const randomColor=()=>{
  const random = Math.random()

  if(random>0&&random<0.3){
    return 'red'
  }else if(random>0.3&&random<0.6){
    return 'blue'
  }else{
    return 'yellow'
  }
  // return `rgba(${random*255},${random*255},${random*255},1)`
}


const drawTable=()=>{
  canvas.value.addEventListener('click',handleClick)

  const ctx=canvas.value.getContext('2d')  //还可以是webgl(这里参考three.js)

  const {columns,dataSource}=data

  // 清除选中
  ctx.clearRect(0,0,1000,750)
  
  const padding = 10

  ctx.beginPath()
  // 画表格

  // 画表头
  for (let i=0; i<columns.length; i++){
    const column=columns[i]
    ctx.font =`bold ${16*pixelRatio}px serif`
    ctx.fillText(column.title,i*cellWidth+padding,cellHeight/2)
    console.log("column",column);
  } 

  // 表格
  for (let i=startRow; i<startRow+visableRows; i++){
    const record=dataSource[i]
    for (let j=0; j<columns.length; j++){
      // 做判断，如果被选中了，那么就需要画矩形来高亮单元格
      const column=columns[j]
      // 先画背景
      // 画矩形其实是一个fill填充操作
      if(selectedCell.row===i&&selectedCell.column===j){
        ctx.fillStyle = randomColor()
        ctx.fillRect(j*cellWidth,cellHeight*(i-startRow+1),cellWidth,cellHeight)  //减startRow是因为视窗大小限制，要判断他的相对位置
        ctx.fillStyle = 'black'
      }

      // 再写文字，文字填充
      ctx.font =`${16*pixelRatio}px serif`
      ctx.fillText(record[column.key],j*cellWidth+padding,cellHeight*(i-startRow+1)+cellHeight/2)
      
    }
  } 

  ctx.closePath()

}

// 加滚动条
const handleWheel = ()=>{
  document.addEventListener("wheel", (ev)=>{
    console.log(ev);
    const {deltaY}=ev
    if(deltaY<0){
      // startRow-=1
      // if(startRow<0){
      //   startRow=0
      // }
      startRow=Math.max(0,startRow-1)
    }else{
      // startRow+=1
      // if(startRow+visableRows>data.dataSource.length){
      //   startRow=data.dataSource.length-visableRows
      // }
      startRow=Math.min(data.dataSource.length-visableRows,startRow+1)
    }
    drawTable()
  },false)
}

const handleSearch=(ev)=>{
  const {value}=ev.target
  // data.dataSource.filter((item)=>item.name.includes(value))
  // vue中间数组的操作，一定要注意
  // 太大变动会导致Vue重新渲染(rerender)

  // 但是我们现在不同，因为我们使用的是canvas Table的方案
  data.dataSource=data.tmpDataSource.filter((item)=>item.name.includes(value))
}


onMounted(() => { 
  drawTable()
  
  handleWheel()
});


watch(
  // 监听data中的dataSource，并重新绘制
  () => data.dataSource,
  ()=>drawTable()
)


onUnmounted(() => {
  canvas.value?.removeEventListener('click',handleClick)
})
</script>

<style scoped>
canvas{
  background-color: #eee;
  width: 800px;   /* 这个是正常宽度 */
  height: 600px;  /* 这个是正常高度 */
}
</style>